using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using System.Xml;
using System.IO;
using System.Xml.Serialization;


namespace Ziggyware.XNAFont
{
    [Serializable]
    [XmlRoot()]
    public class Fonts : IDisposable
    {
        [XmlIgnore()]
        public Texture2D Texture;


        [XmlIgnore()]
        SpriteBatch fontRenderer;

        string fontFamily;
        public string FontFamily
        {
            get { return fontFamily; }
            set { fontFamily = value; }
        }

        int height;
        public int Height 
        {
            get { return height; }
            set { height = value; }
        }

        int kerning = 0;
        public int Kerning
        {
            get { return kerning; }
            set { kerning = value; }
        }

        [Serializable()]
        public class XNAFontUV
        {
            [XmlAttribute()]
            public int U;

            [XmlAttribute()]
            public int V;

            [XmlAttribute()]
            public int Width;

            [XmlAttribute()]
            public char C;

            public XNAFontUV() 
            {
                U = 0;
                V = 0;
                Width = 0;
                C = (char)0;
            }

            public XNAFontUV(int u, int v, char c, int Width)
            {
                this.U = u;
                this.V = v;
                this.C = c;
                this.Width = Width;
            }
        }

        [XmlIgnore()]
        public Dictionary<char, XNAFontUV> UVData = new Dictionary<char, XNAFontUV>();

        public List<XNAFontUV> UVList;

        

        public void OutputText(string str, int x, int y, Color col)
        {
            int iCurrentX = x;
            int iCurrentY = y;

            fontRenderer.Begin(SpriteBlendMode.AlphaBlend);
            foreach (char c in str)
            {
                XNAFontUV uv = UVData[c];

                if (c != ' ')
                {
                    fontRenderer.Draw(Texture,
                        new Rectangle(iCurrentX, iCurrentY,
                            uv.Width, height),
                        new Rectangle(uv.V-2,
                                      uv.U,
                                      uv.Width, height),
                        col);
                }

                iCurrentX += uv.Width - kerning;
            }
            fontRenderer.End();
        }

        public static Fonts LoadFont(GraphicsDevice device, string strXML)
        {
            XmlSerializer fontLoader = new XmlSerializer(typeof(Fonts));

            Stream reader = new FileStream(strXML, FileMode.Open);

            Fonts ret = (Fonts)fontLoader.Deserialize(reader);

            reader.Close();

            ret.UVData = new Dictionary<char, XNAFontUV>();
            foreach (XNAFontUV uv in ret.UVList)
            {
                ret.UVData.Add(uv.C, uv);
            }

            ret.UVList = null;

            ret.Texture = Texture2D.FromFile(device, strXML + ".dds");
            ret.fontRenderer = new SpriteBatch(device);

            return ret;
        }

        public void SaveFont(string strXML)
        {

            Texture.Save(strXML + ".dds", ImageFileFormat.Dds);

            XmlSerializer fontWriter = new XmlSerializer(typeof(Fonts));

            Stream outputStream = File.Open(strXML, FileMode.Create);

            Dictionary<char, XNAFontUV>.Enumerator iter = UVData.GetEnumerator();

            UVList = new List<XNAFontUV>();

            while (iter.MoveNext())
            {
                
                UVList.Add(iter.Current.Value);
            }


            fontWriter.Serialize(outputStream, this);

            outputStream.Close();

            UVList = null;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (Texture != null)
                Texture.Dispose();

            if (fontRenderer != null)
                fontRenderer.Dispose();

            Texture = null;
            fontRenderer = null;
        }

        #endregion
    }
}
